/*
 * @Author: Morphlng
 * @Date: 2022-04-06 09:11:05
 * @LastEditTime: 2022-04-06 18:50:27
 * @LastEditors: Morphlng
 * @Description: A finally emulation in C++, using RAII feature.
 * @FilePath: \Cish\useful_trick\finally.h
 */
#pragma once
#include <utility>

template <class F>
class final_action
{
public:
    explicit final_action(F action) noexcept
        : action_(std::move(action)),
          invoke_(true)
    {
    }

    final_action(final_action &&other) noexcept
        : action_(std::move(other.action_)),
          invoke_(other.invoke_)
    {
        other.invoke_ = false;
    }

    virtual ~final_action() noexcept
    {
        if (invoke_)
            action_();
    }

    final_action(final_action const &) = delete;
    final_action &operator=(final_action const &) = delete;
    final_action &operator=(final_action &&) = delete;

protected:
    void disable() noexcept
    {
        invoke_ = false;
    }

private:
    F action_;
    bool invoke_;
};

template <class F>
[[nodiscard]] inline final_action<F>
finally(F const &action) noexcept
{
    return final_action<F>(action);
}

template <class F>
[[nodiscard]] inline final_action<F>
finally(F &&action) noexcept
{
    return final_action<F>(std::forward<F>(action));
}